SpringBoot中yml与properties配置文件及bean取值赋值

您所在的位置:网站首页 java bean和spring bean SpringBoot中yml与properties配置文件及bean取值赋值

SpringBoot中yml与properties配置文件及bean取值赋值

2024-07-15 11:15:10| 来源: 网络整理| 查看: 265

① SpringBoot的配置文件

SpringBoot使用一个全局的配置文件,配置文件名是固定的 :

application.propertiesapplication.yml

配置文件的作用 : 修改SpringBoot自动配置的默认值(SpringBoot在底层已经配置好的属性)。

② yml 是什么?

YAML(YAML Ain’t Markup Language) YAML A Markup Language:是一个标记语言 YAML isn’t Markup Language:不是一个标记语言;

YAML:以数据为中心,比json、xml等更适合做配置文件。

配置例子-更改Tomcat默认端口 :

server: port:8081 ③ YAML语法

YAML使用缩进表示层级关系,缩进时不允许使用Tab键,只允许使用空格。缩进的空格的数目不重要,只要相同层级的元素左侧对齐即可。

YAML支持三种数据结构 :

对象 : 键值对的集合;数组 : 一组按次序排列的值;字面量 : 单个的不可分割的值。

语法格式如下 :

k:(空格)v;表示一对键值对,空格必须有。 server: port: 8082 ④ YAML值的写法

一般值有三种类型 : 字面量,即普通的值(数字,字符串,布尔);对象、map(键值对);数组(list set)。

(4.1)字面量

k: v:字面直接来写;

字符串默认不用加上单引号或者双引号;

“”:双引号;不会转义字符串里面的特殊字符;特殊字符会作为本身想表示的意思

name: "zhangsan \n lisi";输出:zhangsan 换行 lisi;

‘’:单引号;会转义特殊字符,特殊字符最终只是一个普通的字符串数据

name: ‘zhangsan \n lisi’; 输出:zhangsan \n lisi

(4.2)对象、map

k: v:在下一行来写对象的属性和值的关系;注意缩进 对象还是k: v的方式

friends: lastName: zhangsan age: 20

行内写法:

friends: {lastName: zhangsan,age: 18}

(4.3)数组

用- 值表示数组中的一个元素

pets: ‐ cat ‐ dog ‐ pig

行内写法

pets: [cat,dog,pig] ⑤ 使用yml为bean赋值 (5.1) 添加文件处理器依赖

官网如下 : https://docs.spring.io/spring-boot/docs/2.0.2.RELEASE/reference/html/configuration-metadata.html#configuration-metadata-annotation-processor

org.springframework.boot spring-boot-configuration-processor true

这里写图片描述

(5.2)JavaBean注解配置

@ConfigurationProperties:告诉SpringBoot将本类中的所有属性和配置文件中相关的配置进行绑定。

prefix = "person":配置文件中哪个下面的所有属性进行一一映射。

该注解默认从全局配置文件中取值。

/** * 将配置文件中配置的每一个属性的值,映射到这个组件中 * @ConfigurationProperties:告诉SpringBoot将本类中的所有属性 * 和配置文件中相关的配置进行绑定; * prefix = "person":配置文件中哪个下面的所有属性进行一一映射 * 只有这个组件是容器中的组件,才能容器提供的@ConfigurationProperties功能; */ @Component @ConfigurationProperties(prefix = "person") public class Person { private String lastName; private Integer age; private Boolean boss; private Date birth; private Map maps; private List lists; private Dog dog; //... // 注意,@ConfigurationProperties该注解时不用再使用@Value!!! } (5.3)编写yml配置文件 server: port: 8082 person: lastName: hello age: 18 boss: false birth: 2017/12/12 maps: {k1: v1,k2: 12} lists: ‐ lisi ‐ zhaoliu dog: name: 小狗 age: 12 (5.4)使用SpringBoot 测试 @RunWith(SpringRunner.class) @SpringBootTest public class SpringbooHelloworldQuickApplicationTests { @Autowired Person person; @Test public void contextLoads() { System.out.println(person); } }

测试结果如下所示 :

这里写图片描述

Spring容器中的bean被yml中的配置正确赋值!

(5.5)使用@ConfigurationProperties注解的同时使用@Value @Component @ConfigurationProperties(prefix = "person") public class Person { @Value("${person.age}") private String lastName; //... }

如上所示,使用@Value为属性赋值别的变量的值。测试结果表明仍然为@ConfigurationProperties该注解为lastName赋值,@Value注解此时不会起作用。

这里写图片描述

⑥ properties配置文件(仍旧使用@ConfigurationProperties)

properties配置文件是以前项目中常用的配置文件,SpringBoot同样保留了该种类型的配置文件。

如下所示,在properties文件中为person赋值:

# idea person.age=21 person.birth=2018/11/11 person.last-name=小明 person.boss=true person.dog.name=dog person.dog.age=1 person.maps.k1=v1 person.maps.k2=v2 person.lists=a,b,c

运行测试 :

这里写图片描述

正常获取到值,但是中文乱码,为什么?

应该项目中都遇到这样的例子,读取properties文件中的中文乱码。以前解决办法就是将properties文件中的中文转换为Unicode形式,如\u822a\u6bcd。或者将其重新编码再解码。

idea中解决方法如下图:

将其转换为ASCII,其与Unicode是可以相互转换的。

这里写图片描述

再次测试:

这里写图片描述

⑦ @Value为bean赋值

在以前的项目中常用为bean赋值(从properties文件中获取值)的方法有两种。

第一种-xml配置

示例如下

第二种-@Value @Component public class Person { /** * * * */ //lastName必须是邮箱格式 // @Email// 不支持JSR303校验 @Value("${person.last-name}")//键必须与properties文件中的一致 private String lastName; @Value("#{11*2}")//支持SpELl语法 private Integer age; @Value("true") private Boolean boss; private Date birth; // @Value("${person.maps}")//不支持复杂类型封装 private Map maps; private List lists; private Dog dog; //... }

@Value默认从系统环境中加载属性变量。比如application.yml中配置了person.lastName属性,那么就可以使用@Value直接为Person的lastName赋值。

@Value注入map或者list

配置文件如下:

list: topic1,topic2,topic3 maps: "{key1: 'value1', key2: 'value2'}"

注入实例如下:

@Value("#{'${list}'.split(',')}") private List list; @Value("#{${maps}}") private Map maps; ⑧ @Value获取值和@ConfigurationProperties获取值比较

松散绑定 :

–person.firstName:使用标准方式 –person.first-name:大写用- –person.first_name:大写用_ –PERSON_FIRST_NAME: .推荐系统属性使用这种写法

上面几种写法在@ConfigurationProperties环境下都可以对应到person对象的firstName属性。@Value则必须保证取的键与properties文件中一致。

JSR303校验:

@Component @ConfigurationProperties(prefix = "person") @Validated public class Person { //lastName必须是邮箱格式 // @Value("${person.last-name}") @Email private String lastName; //... }

@Value 不支持JSR3030校验,但是支持SpELl语法,@ConfigurationProperties则相反。

对比总结如下:

这里写图片描述

总结如下:

配置文件yml还是properties他们都能获取到值;

如果说,我们只是在某个业务逻辑中需要获取一下配置文件中的某项值,使用@Value;

如果说,我们专门编写了一个javaBean来和配置文件进行映射,我们就直接使用@ConfigurationProperties;

那么能否在业务逻辑类中使用@ConfigurationProperties呢?

不建议使用,@ConfigurationProperties会将本类中的所有属性和配置文件中相关的配置进行绑定。尤其@ConfigurationProperties支持松散语法。

⑨ @PropertySource加载额外的配置文件

将一切配置全部写在全局配置文件中,是不可想象的。项目中不可避免存在多个配置文件。

@PropertySource就可以根据需要加载指定的配置文件(@ConfigurationProperties 默认从全局配置文件获取配置),将配置文件中的属性注入到系统环境中。

这里将person的属性配置单独写在person.properties文件中,并从全局配置文件中注释掉person的属性配置。

这里写图片描述

Person中使用@Value为属性赋值:

@PropertySource(value = {"classpath:person.properties"}) @Component public class Person { /** * * * */ //lastName必须是邮箱格式 // @Email @Value("${person.last-name}") private String lastName; @Value("${person.age}") private Integer age; @Value("true") private Boolean boss; @Value("${person.birth}") private Date birth; @Value("${person.maps}") private Map maps; @Value("${person.lists}") private List lists; @Value("${person.dog}") private Dog dog;

为了对比person的属性从不同配置文件赋值,这里将全局配置文件中保留person.lastName属姓配置。

测试如下:

这里写图片描述

分析可知,默认从全局配置文件中为person赋值,这里为lastName赋值小明。person的其他属性从person.properties文件中获取。

同时使用@PropertySource和@ConfigurationProperties注解,则默认属性仍旧从全局配置文件寻找,其次从@PropertySource指定的配置文件寻找。而且Person中的属性 不用 再使用@Value为其赋值。

@PropertySource(value = {"classpath:person.properties"}) @Component @ConfigurationProperties(prefix = "person") public class Person { private String lastName; private Integer age; private Boolean boss; //... }

application.properties如下图: 这里写图片描述 person.properties如下图: 这里写图片描述 测试结果如下图:

这里写图片描述

⑩ 多个配置文件同属性配置@Value取值

如果项目中不同配置文件中配置同属性,使用@Value该如何取值呢?这就涉及到了配置文件加载优先级的问题。

如图一:

这里写图片描述

application.properties与person.properties同时配置了属性person.last-name,如图中所示,使用@Value取值,此时取到的值为application.properties中的值。

若将application.properties中的person.last-name注释掉,则取的为person.properties(Person类配置了@PropertySource)值。

那么是否说明,默认从全局配置文件取还是按照上下顺序依次检查呢?

如图二所示:

这里写图片描述

修改application.properties为tapplication.properties文件,将会从application.yml到tapplication.properties依次查找,如找到该属性则取其值。

那么是否能够说明了配置文件的加载次序呢?

参考博客:SpringBoot配置文件加载位置与优先级。

(11)@ImportResource导入Spring配置xml文件

Spring Boot里面没有Spring的配置文件,我们自己编写的配置文件,也不能自动识别。那么如何使用我们自己编写的配置文件呢?

在主配置类添加@ImportResource注解,如下图:

这里写图片描述

配置文件内容如下:

测试如下:

这里写图片描述

在主配置类使用ImportResource引入自定义Spring配置文件,即可获取helloService bean。

(12)SpringBoot推荐给容器中添加组件的方式

SpringBoot推荐使用配置类的方式来给容器中添加组件。如下所示:

@Configuration public class MyAppConfig { //将方法的返回值添加到容器中;容器中这个组件默认的id就是方法名 @Bean public HelloService helloService(){ System.out.println("配置类@Bean给容器中添加组件了..."); return new HelloService(); } }

测试结果如下图: 这里写图片描述

(13)配置文件占位符

除了前面说的几种方式,还可以使用占位符的方式在配置文件中为属性赋值。

① 随机数

示例如下:

person.last‐name=张三${random.uuid}

② 占位符获取之前配置的值,如果没有可以是用:指定默认值

示例如下:

person.last‐name=张三${random.uuid} person.age=${random.int} person.birth=2017/12/15 person.boss=false person.maps.k1=v1 person.maps.k2=14 person.lists=a,b,c person.dog.name=${person.hello:hello}_dog person.dog.age=15

${person.hello:hello}意思为如果person.hello没有值则默认赋值为hello。${person.hello}如果有值,则取值,无值则会当作字面量解析–${person.hello}原样赋值。

(14)@PropertySource和@ConfigurationProperties以及@Value

这三个注解究竟是什么,做了什么?

① @Value

源码如下:

/** * Annotation at the field or method/constructor parameter level * that indicates a default value expression for the affected argument. * *

Typically used for expression-driven dependency injection. Also supported * for dynamic resolution of handler method parameters, e.g. in Spring MVC. * *

A common use case is to assign default field values using * "#{systemProperties.myProp}" style expressions. * *

Note that actual processing of the {@code @Value} annotation is performed * by a {@link org.springframework.beans.factory.config.BeanPostProcessor * BeanPostProcessor} which in turn means that you cannot use * {@code @Value} within * {@link org.springframework.beans.factory.config.BeanPostProcessor * BeanPostProcessor} or * {@link org.springframework.beans.factory.config.BeanFactoryPostProcessor BeanFactoryPostProcessor} * types. Please consult the javadoc for the {@link AutowiredAnnotationBeanPostProcessor} * class (which, by default, checks for the presence of this annotation). * * @author Juergen Hoeller * @since 3.0 * @see AutowiredAnnotationBeanPostProcessor * @see Autowired * @see org.springframework.beans.factory.config.BeanExpressionResolver * @see org.springframework.beans.factory.support.AutowireCandidateResolver#getSuggestedValue */ @Target({ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented public @interface Value { /** * The actual value expression: e.g. "#{systemProperties.myProp}". */ String value(); }

言简意赅说一下,这个注解可以动态为属性赋值,处理过程是BeanPostProcessor!

② @PropertySource

源码如下:

/** * Annotation providing a convenient and declarative mechanism for adding a * {@link org.springframework.core.env.PropertySource PropertySource} to Spring's * {@link org.springframework.core.env.Environment Environment}. To be used in * conjunction with @{@link Configuration} classes. * * Example usage * *

Given a file {@code app.properties} containing the key/value pair * {@code testbean.name=myTestBean}, the following {@code @Configuration} class * uses {@code @PropertySource} to contribute {@code app.properties} to the * {@code Environment}'s set of {@code PropertySources}. * * * @Configuration * @PropertySource("classpath:/com/myco/app.properties") * public class AppConfig { * @Autowired * Environment env; * * @Bean * public TestBean testBean() { * TestBean testBean = new TestBean(); * testBean.setName(env.getProperty("testbean.name")); * return testBean; * } * } * * Notice that the {@code Environment} object is @{@link * org.springframework.beans.factory.annotation.Autowired Autowired} into the * configuration class and then used when populating the {@code TestBean} object. Given * the configuration above, a call to {@code testBean.getName()} will return "myTestBean". * * Resolving ${...} placeholders in {@code } and {@code @Value} annotations * * In order to resolve ${...} placeholders in {@code } definitions or {@code @Value} * annotations using properties from a {@code PropertySource}, one must register * a {@code PropertySourcesPlaceholderConfigurer}. This happens automatically when using * {@code } in XML, but must be explicitly registered using * a {@code static} {@code @Bean} method when using {@code @Configuration} classes. See * the "Working with externalized values" section of @{@link Configuration}'s javadoc and * "a note on BeanFactoryPostProcessor-returning @Bean methods" of @{@link Bean}'s javadoc * for details and examples. * * Resolving ${...} placeholders within {@code @PropertySource} resource locations * * Any ${...} placeholders present in a {@code @PropertySource} {@linkplain #value() * resource location} will be resolved against the set of property sources already * registered against the environment. For example: * * * @Configuration * @PropertySource("classpath:/com/${my.placeholder:default/path}/app.properties") * public class AppConfig { * @Autowired * Environment env; * * @Bean * public TestBean testBean() { * TestBean testBean = new TestBean(); * testBean.setName(env.getProperty("testbean.name")); * return testBean; * } * } * * Assuming that "my.placeholder" is present in one of the property sources already * registered, e.g. system properties or environment variables, the placeholder will * be resolved to the corresponding value. If not, then "default/path" will be used as a * default. Expressing a default value (delimited by colon ":") is optional. If no * default is specified and a property cannot be resolved, an {@code * IllegalArgumentException} will be thrown. * * A note on property overriding with @PropertySource * * In cases where a given property key exists in more than one {@code .properties} * file, the last {@code @PropertySource} annotation processed will 'win' and override. * * For example, given two properties files {@code a.properties} and * {@code b.properties}, consider the following two configuration classes * that reference them with {@code @PropertySource} annotations: * * * @Configuration * @PropertySource("classpath:/com/myco/a.properties") * public class ConfigA { } * * @Configuration * @PropertySource("classpath:/com/myco/b.properties") * public class ConfigB { } * * * The override ordering depends on the order in which these classes are registered * with the application context. * * AnnotationConfigApplicationContext ctx = * new AnnotationConfigApplicationContext(); * ctx.register(ConfigA.class); * ctx.register(ConfigB.class); * ctx.refresh(); * * * In the scenario above, the properties in {@code b.properties} will override any * duplicates that exist in {@code a.properties}, because {@code ConfigB} was registered * last. * *

In certain situations, it may not be possible or practical to tightly control * property source ordering when using {@code @ProperySource} annotations. For example, * if the {@code @Configuration} classes above were registered via component-scanning, * the ordering is difficult to predict. In such cases - and if overriding is important - * it is recommended that the user fall back to using the programmatic PropertySource API. * See {@link org.springframework.core.env.ConfigurableEnvironment ConfigurableEnvironment} * and {@link org.springframework.core.env.MutablePropertySources MutablePropertySources} * javadocs for details. * * @author Chris Beams * @author Juergen Hoeller * @author Phillip Webb * @since 3.1 * @see PropertySources * @see Configuration * @see org.springframework.core.env.PropertySource * @see org.springframework.core.env.ConfigurableEnvironment#getPropertySources() * @see org.springframework.core.env.MutablePropertySources */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @Documented @Repeatable(PropertySources.class) public @interface PropertySource { /** * Indicate the name of this property source. If omitted, a name will * be generated based on the description of the underlying resource. * @see org.springframework.core.env.PropertySource#getName() * @see org.springframework.core.io.Resource#getDescription() */ String name() default ""; /** * Indicate the resource location(s) of the properties file to be loaded. * For example, {@code "classpath:/com/myco/app.properties"} or * {@code "file:/path/to/file"}. *

Resource location wildcards (e.g. **/*.properties) are not permitted; * each location must evaluate to exactly one {@code .properties} resource. *

${...} placeholders will be resolved against any/all property sources already * registered with the {@code Environment}. See {@linkplain PropertySource above} * for examples. *

Each location will be added to the enclosing {@code Environment} as its own * property source, and in the order declared. */ String[] value(); /** * Indicate if failure to find the a {@link #value() property resource} should be * ignored. *

{@code true} is appropriate if the properties file is completely optional. * Default is {@code false}. * @since 4.0 */ boolean ignoreResourceNotFound() default false; /** * A specific character encoding for the given resources, e.g. "UTF-8". * @since 4.3 */ String encoding() default ""; /** * Specify a custom {@link PropertySourceFactory}, if any. *

By default, a default factory for standard resource files will be used. * @since 4.3 * @see org.springframework.core.io.support.DefaultPropertySourceFactory * @see org.springframework.core.io.support.ResourcePropertySource */ Class> converters = Collections.emptyList(); private List genericConverters = Collections.emptyList(); private int order = Ordered.HIGHEST_PRECEDENCE + 1; /** * A list of custom converters (in addition to the defaults) to use when converting * properties for binding. * @param converters the converters to set */ @Autowired(required = false) @ConfigurationPropertiesBinding public void setConverters(List converter : this.converters) { conversionService.addConverter(converter); } for (GenericConverter genericConverter : this.genericConverters) { conversionService.addConverter(genericConverter); } this.defaultConversionService = conversionService; } return this.defaultConversionService; } /** * {@link LocalValidatorFactoryBean} supports classes annotated with * {@link Validated @Validated}. */ private static class ValidatedLocalValidatorFactoryBean extends LocalValidatorFactoryBean { private static final Log logger = LogFactory .getLog(ConfigurationPropertiesBindingPostProcessor.class); ValidatedLocalValidatorFactoryBean(ApplicationContext applicationContext) { setApplicationContext(applicationContext); setMessageInterpolator(new MessageInterpolatorFactory().getObject()); afterPropertiesSet(); } @Override public boolean supports(Class type) { if (!super.supports(type)) { return false; } if (AnnotatedElementUtils.hasAnnotation(type, Validated.class)) { return true; } if (type.getPackage() != null && type.getPackage().getName() .startsWith("org.springframework.boot")) { return false; } if (getConstraintsForClass(type).isBeanConstrained()) { logger.warn("The @ConfigurationProperties bean " + type + " contains validation constraints but had not been annotated " + "with @Validated."); } return true; } } /** * {@link Validator} implementation that wraps {@link Validator} instances and chains * their execution. */ private static class ChainingValidator implements Validator { private Validator[] validators; ChainingValidator(Validator... validators) { Assert.notNull(validators, "Validators must not be null"); this.validators = validators; } @Override public boolean supports(Class clazz) { for (Validator validator : this.validators) { if (validator.supports(clazz)) { return true; } } return false; } @Override public void validate(Object target, Errors errors) { for (Validator validator : this.validators) { if (validator.supports(target.getClass())) { validator.validate(target, errors); } } } } /** * Convenience class to flatten out a tree of property sources without losing the * reference to the backing data (which can therefore be updated in the background). */ private static class FlatPropertySources implements PropertySources { private PropertySources propertySources; FlatPropertySources(PropertySources propertySources) { this.propertySources = propertySources; } @Override public Iterator get(String name) { return getFlattened().get(name); } private MutablePropertySources getFlattened() { MutablePropertySources result = new MutablePropertySources(); for (PropertySource propertySource : this.propertySources) { flattenPropertySources(propertySource, result); } return result; } private void flattenPropertySources(PropertySource propertySource, MutablePropertySources result) { Object source = propertySource.getSource(); if (source instanceof ConfigurableEnvironment) { ConfigurableEnvironment environment = (ConfigurableEnvironment) source; for (PropertySource childSource : environment.getPropertySources()) { flattenPropertySources(childSource, result); } } else { result.addLast(propertySource); } } } }

可以发现这个类实现了我们很多眼熟的接口:

public class ConfigurationPropertiesBindingPostProcessor implements BeanPostProcessor, BeanFactoryAware, EnvironmentAware, ApplicationContextAware, InitializingBean,DisposableBean, ApplicationListener, PriorityOrdered { //... }

大概就是在bean的属性赋值、初始化前后进行的操作,具体参考博文bean的初始化和销毁过程详解。

(15) springboot下外部xml文件引用application.properties配置 ① 不适用context:property-placeholder或者PropertyPlaceholderConfigurer

在这里插入图片描述

如下所示,spring.xml文件尝试引用XXXX.properites中属性配置。

因为application.properties中配置了spring.profiles.active=env ,那么就会从application-env.properties查找com.jane.appid.test配置。否则,从application.properties中查找。

② 使用context:property-placeholder

此时的查找顺序

① 从application-env.properties查找,如果找到不再往下查找;② 从application-test.properties中查找;③ 如果①没有找到,②找到了,则使用②的值。否则使用①的值。


【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭